import { dom } from '@knno/dom';
import { addAttachListener, removeAttachListener } from '../../tools/monitor';
import { takeIf } from '../../tools/sugar';
import { FormItem } from '../interface';
import { Validatable } from '../validatable';
import { LINE_HEIGHT, PADDING, textareaStyle } from './textarea.css';

function doResize(area: HTMLTextAreaElement) {
	if (!area.isConnected) return;
	area.style.height = '';
	const style = window.getComputedStyle(area);
	const height = area.scrollHeight;
	area.style.height = height + 'px';
	const maxHeight = parseFloat(style.maxHeight);
	if (height > maxHeight + 1) {
		area.style.overflow = 'auto';
	} else {
		area.style.overflow = '';
	}
}
function onResize(evt: Event) {
	const area = evt.target as HTMLTextAreaElement;
	doResize(area);
}

export type ResizeType = 'fixed' | 'auto' | 'manual';

export class Textarea extends Validatable implements FormItem {
	constructor() {
		super(dom.textarea(textareaStyle).attr('resize', 'auto'));
		this.on('input', (evt) => {
			this.invalid(false);
			if (this.resize() === 'auto') {
				onResize(evt);
			}
		});
		this.on('change', () => {
			this.invalid(false);
		});
		addAttachListener(this[0], () => {
			doResize(this[0] as HTMLTextAreaElement);
			removeAttachListener(this[0]);
		});
	}

	placeholder(): string;
	placeholder(text: string): this;
	placeholder(text?: string): this | string | undefined {
		if (typeof text === 'string') {
			this.prop('placeholder', text);
			return this;
		}
		return this.prop('placeholder') as string;
	}

	disabled(): boolean;
	disabled(value: boolean): this;
	disabled(value?: boolean): boolean | this {
		if (value === undefined) {
			return this.attr('disabled') != null;
		}
		return this.attr('disabled', value);
	}

	readonly(): boolean;
	readonly(value: boolean): this;
	readonly(value?: boolean): boolean | this {
		if (value === undefined) {
			return this.attr('readonly') != null;
		}
		this.attr('readonly', value);
		return this;
	}

	maxLength(): number | null;
	maxLength(len: number | null): this;
	maxLength(len?: number | null): this | number | null {
		if (len !== undefined) {
			this.attr('maxlength', len ? len + '' : null);
			return this;
		}
		return takeIf(this.attr('maxlength'), (v) => parseInt(v)) ?? null;
	}

	lines(len: number | null): this {
		if (typeof len === 'number' && len > 0) {
			this.css('minHeight', `calc(${len * LINE_HEIGHT}rem + ${PADDING * 2}em)`);
		} else {
			this.css('minHeight', '');
		}
		return this;
	}

	maxLines(len: number | null): this {
		if (typeof len === 'number' && len > 0) {
			this.css('maxHeight', `calc(${len * LINE_HEIGHT}rem + ${PADDING * 2}em)`);
		} else {
			this.css('maxHeight', '');
		}
		return this;
	}

	resize(): ResizeType;
	resize(value: ResizeType): this;
	resize(value?: ResizeType): ResizeType | this {
		if (value === undefined) {
			const t = this.attr('resize') ?? 'auto';
			return (/^(auto|fixed|manual)$/.test(t) ? t : 'auto') as ResizeType;
		}
		this.attr('resize', value);
		doResize(this[0] as HTMLTextAreaElement);
		return this;
	}

	override text(): string;
	override text(text: string): this;
	override text(text?: string): this | string | undefined {
		if (typeof text === 'string') {
			this.value(text);
			return this;
		}
		return this.value() as string;
	}

	override value(): unknown;
	override value(val: unknown): this;
	override value(val?: unknown): this | unknown | undefined {
		if (typeof val === 'string') {
			super.value(val);
			doResize(this[0] as HTMLTextAreaElement);
			return this;
		}
		return super.value() as string;
	}
}

export function textarea(...className: string[]): Textarea {
	return new Textarea().addClass(...className);
}
